/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkHttpClientPool.h"
#include "MkHttp/MkHttpClient.h"
#include "MkEvent/MkEventPool.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkLog.h"

CMkHttpClientPool::CMkHttpClientPool(CMkEventPool* pEventPool, CMkTimer* pTimer)
    : m_pEventPool(pEventPool)
    , m_pTimer(pTimer)
{

}

CMkHttpClient* CMkHttpClientPool::GetFreeClient()
{
    CMkHttpClient *pClient = nullptr;
    m_ClientLock.Lock();
    MkVector<CMkHttpClient*>::iterator it = m_VecHttpClient.begin();
    for (; it != m_VecHttpClient.end(); it++) {
        if (*it && (*it)->IsFree()) {
            pClient = *it;
            pClient->SetNotFree();
            break;
        }
    }
    if (it == m_VecHttpClient.end()) {
        pClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
            m_ClientLock.Lock();
            MkVector<CMkHttpClient*>::iterator itVec = m_VecHttpClient.begin();
            for (; itVec != m_VecHttpClient.end(); itVec++) {
                if (*itVec == pClient) {
                    m_VecHttpClient.erase(itVec);
                    break;
                }
            }
            m_ClientLock.Unlock();
            pClient->DeleteLater();
        });
        pClient->SetNotFree();
        m_VecHttpClient.emplace_back(pClient);
    }
    //MkDebugLog("http client pool has size:%d\n", m_VecHttpClient.size());
    m_ClientLock.Unlock();
    return pClient;
}

Uint32 CMkHttpClientPool::SendJsonRequest(const MkHttpMethod& Method, const MkString& HttpUrl, const MkMapString& MapParam, const MkMapString& MapHeader, const Json::Value &Request, const MkHttpResponseJsonCb& Cb, Uint32 TimeMilSeconds/* = 5000*/)
{
    MkString strReqBody;
    if (!Request.empty()) {
        strReqBody = Request.toStyledString();
    }
    CMkHttpClient *pClient = GetFreeClient();
    //MkDebugLog("http send request url:%s body:%s\n", HttpUrl.c_str(), strReqBody.c_str());
    return pClient->SendRequest(Method, HttpUrl, MapParam, strReqBody, MapHeader, [this, HttpUrl, Cb](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        //MkDebugLog("http url:%s client recv status:%d res:%s\n", HttpUrl.c_str(), StatusCode, Res.c_str());
        Uint32 ErrorCode = HttpResponseErrorBegin + StatusCode; //default time out
        Json::Value JsonResBody = Json::Value();
        if (MkHttpStateOk == StatusCode) {
            Json::Value JsonResponse;
            try {
                Json::CharReaderBuilder b;
                Json::CharReader *reader(b.newCharReader());
                if (!reader) {
                    ErrorCode = MallocFailed;
                } else {
                    MkString errs;
                    reader->parse(Res.c_str(), Res.c_str() + Res.size(), &JsonResponse, &errs);
                    delete reader;
                    ErrorCode = JsonResponse["code"].asInt();
                    MkVector<MkString> MemberNames = JsonResponse.getMemberNames();
                    JsonResBody = JsonResponse["data"];
                    if (JsonResBody.empty() && 1 != MemberNames.size()) {
                        JsonResBody = JsonResponse;
                    }
                }
            } catch (Json::Exception &e) {
                MkErrorLog("body:%s\n", Res.c_str());
                MkErrorLog("json parse error:%s\n", e.what());
                ErrorCode = InvalidParams;
            }
        }
        if (Cb) {
            Cb(ErrorCode, JsonResBody);
        }
    }, TimeMilSeconds);
}

Uint32 CMkHttpClientPool::SendRequest(const MkHttpMethod& Method, const MkString& HttpUrl, const MkMapString& MapParam, const MkString& Body, const MkMapString& MapHeader, const MkHttpResponseCb& ResponseCb, Uint32 TimeMilSeconds/* = 5000*/)
{
    CMkHttpClient *pClient = GetFreeClient();
    return pClient->SendRequest(Method, HttpUrl, MapParam, Body, MapHeader, ResponseCb, TimeMilSeconds);
}

CMkHttpClientPool::~CMkHttpClientPool()
{
    //MkDebugLog("delete client pool:%p\n", this);
    m_ClientLock.Lock();
    MkVector<CMkHttpClient*>::iterator it = m_VecHttpClient.begin();
    for (; it != m_VecHttpClient.end(); it++) {
        //MkDebugLog("delete http client pool item:%p\n", *it);
        MkDelete(*it);
    }
    m_VecHttpClient.clear();
    m_ClientLock.Unlock();
}